package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.remark.RemarkClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.ReplyDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.common.utils.AssertUtils;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.ReplyPageQuery;
import com.tianji.learning.domain.vo.ReplyVO;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.enums.TextModerationServiceType;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.service.IInteractionReplyService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.utils.AliyunTextModerationHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动问题的回答或评论 服务实现类
 * </p>
 *
 * @author LYQ
 * @since 2024-06-25
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class InteractionReplyServiceImpl extends ServiceImpl<InteractionReplyMapper, InteractionReply> implements IInteractionReplyService {
    private final UserClient userClient;
    private final RemarkClient remarkClient;
    private final InteractionQuestionMapper questionMapper;
    private final AliyunTextModerationHandler aliyunTextModerationHandler;

    /**
     * 管理端 - 分页查询回答或评论列表
     *
     * @param pageQuery
     * @return
     */
    @Override
    public PageDTO<ReplyVO> adminQueryPage(ReplyPageQuery pageQuery) {
        //0、数据健壮性校验
        if (ObjectUtils.isEmpty(pageQuery.getAnswerId()) && ObjectUtils.isEmpty(pageQuery.getQuestionId())) {
            throw new BadRequestException("问题id和回答id不能同时为空");
        }
        Page<InteractionReply> pageResult;
        List<InteractionReply> records;
        //1、判断是回答还是评论进行分页查询
        pageResult = this.lambdaQuery()
                .eq(ObjectUtils.isEmpty(pageQuery.getAnswerId()), InteractionReply::getQuestionId, pageQuery.getQuestionId())
                .eq(InteractionReply::getAnswerId, (ObjectUtils.isNotEmpty(pageQuery.getAnswerId()) ? pageQuery.getAnswerId() : 0))//判断是回答还是评论
                .page(pageQuery.toMpPage(
                        new OrderItem("create_time", false),
                        new OrderItem("liked_times", false)));
        records = pageResult.getRecords();
        //2、填充用户昵称、头像、targetUserName等属性
        //2.1、根据回答是否匿名决定是否填充用户昵称与头像
        //2.1.1收集所有用户id、回答/评论id
        List<Long> userIds = new ArrayList<>(records.size());
        List<Long> replyIds = new ArrayList<>(records.size());
        for (InteractionReply record : records) {
            Long userId = record.getUserId();
            userIds.add(userId);
            Long replayId = record.getId();
            replyIds.add(replayId);
        }
        Set<Long> likedList = remarkClient.isLiked(replyIds);
        //2.1.2远程条用User-Service 查询对应的UserInfoList,同时转为Map集合
        List<UserDTO> userInfoList = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userInfoMap = new HashMap<>(userInfoList.size());
        if (ObjectUtils.isNotEmpty(userInfoList)) {
            userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserDTO::getId, Function.identity()));
        }
        //3、遍历转换为Vo填充用户昵称与头像
        List<ReplyVO> voList = new ArrayList<>(records.size());
        for (InteractionReply record : records) {
            ReplyVO vo = BeanUtils.copyBean(record, ReplyVO.class);
            UserDTO userInfo = userInfoMap.get(record.getUserId());
            if (ObjectUtils.isNotEmpty(userInfo)) {
                vo.setUserName(userInfo.getName());
                vo.setUserIcon(userInfo.getIcon());
            } else {
                vo.setUserName("");
                vo.setUserIcon("");
            }
            //3.1、填充是否点赞
            vo.setLiked(likedList.contains(vo.getId()));
            voList.add(vo);
        }
        //4、封装PageDTO返回

        return PageDTO.of(pageResult, voList);
    }


    /**
     * 新增回答或评论
     *
     * @param replyDTO
     */
    @Override
    public void addReply(ReplyDTO replyDTO) {
        //数据健壮性校验
        if (ObjectUtils.isEmpty(replyDTO.getContent()) || ObjectUtils.isEmpty(replyDTO.getQuestionId())) {
            throw new BadRequestException("问题id和回答内容不能为空");
        }
        if (ObjectUtils.isNotEmpty(replyDTO.getAnswerId())) {
            if (ObjectUtils.isEmpty(replyDTO.getTargetReplyId()) || ObjectUtils.isEmpty(replyDTO.getTargetUserId())) {
                throw new BadRequestException("评论时，目标回复id和目标用户id不能为空");
            }
        }
        //阿里云文本检测plus
        String label = aliyunTextModerationHandler.textModeration(replyDTO.getContent(), TextModerationServiceType.LLM_QUERY_MODERATION);
        if (ObjectUtils.isNotEmpty(label) && !label.equals("nonLabel")) {
            throw new BadRequestException("提问内容包含违规内容:" + label);
        }

        //1、构建回答或评论对象
        //1.1初始化Reply对象
        //1.2拷贝前端传递参数
        InteractionReply interactionReply = BeanUtils.copyBean(replyDTO, InteractionReply.class);
        //1.3设置UserId
        interactionReply.setUserId(UserContext.getUser());
        //2、将回答或评论写入数据库
        this.save(interactionReply);
        //3、判断是否是回答
        if (ObjectUtils.isEmpty(replyDTO.getAnswerId())) {
            //4、如果是回答则修改问题表最后一次回答的id，增加回答次数
            questionMapper.update(null, new LambdaUpdateWrapper<InteractionQuestion>()
                    .eq(InteractionQuestion::getId, replyDTO.getQuestionId()) // 设置更新条件
                    .set(InteractionQuestion::getStatus, QuestionStatus.UN_CHECK) //4.1、如果是学生提交，将问题表状态改为未查看（供管理端查看）
                    .set(InteractionQuestion::getLatestAnswerId, interactionReply.getId())
                    .setSql("answer_times  = answer_times + 1"));
        } else {
            //5、如果不是回答而是评论，增加对应回答下评论的次数
            this.update(new LambdaUpdateWrapper<InteractionReply>()
                    .eq(InteractionReply::getId, replyDTO.getAnswerId())
                    .setSql("reply_times  = reply_times + 1"));
        }
    }

    /**
     * 用户端 - 分页查询回答或评论列表
     *
     * @param pageQuery
     */
    @Override
    public PageDTO<ReplyVO> replypage(ReplyPageQuery pageQuery) {
        //0、数据健壮性校验
        if (ObjectUtils.isEmpty(pageQuery.getAnswerId()) && ObjectUtils.isEmpty(pageQuery.getQuestionId())) {
            throw new BadRequestException("问题id和回答id不能同时为空");
        }
        Page<InteractionReply> pageResult;
        List<InteractionReply> records;
        //1、判断是回答还是评论进行分页查询
        pageResult = this.lambdaQuery()
                .eq(ObjectUtils.isEmpty(pageQuery.getAnswerId()), InteractionReply::getQuestionId, pageQuery.getQuestionId())
                .eq(InteractionReply::getAnswerId, (ObjectUtils.isNotEmpty(pageQuery.getAnswerId()) ? pageQuery.getAnswerId() : 0L))//判断是回答还是评论
                .eq(InteractionReply::getHidden, false)
                .page(pageQuery.toMpPage(
                        new OrderItem("create_time", false),
                        new OrderItem("liked_times", false)));
        records = pageResult.getRecords();
        //2、填充用户昵称、头像、targetUserName等属性
        //2.1、根据回答是否匿名决定是否填充用户昵称与头像
        //2.1.1收集所有非匿名用户id
        List<Long> userIds = new ArrayList<>(records.size());
        List<Long> replyIds = new ArrayList<>(records.size());
        for (InteractionReply record : records) {
            if (!record.getAnonymity()) {
                Long userId = record.getUserId();
                userIds.add(userId);
            }
            Long replayId = record.getId();
            replyIds.add(replayId);
        }
        Set<Long> likedList = remarkClient.isLiked(replyIds);
        //2.1.2远程条用User-Service 查询对应的UserInfoList,同时转为Map集合
        List<UserDTO> userInfoList = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userInfoMap = new HashMap<>(userInfoList.size());
        if (ObjectUtils.isNotEmpty(userInfoList)) {
            userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserDTO::getId, Function.identity()));
        }
        //3、遍历转换为Vo填充用户昵称与头像
        List<ReplyVO> voList = new ArrayList<>(records.size());
        for (InteractionReply record : records) {
            ReplyVO vo = BeanUtils.copyBean(record, ReplyVO.class);
            if (!record.getAnonymity()) {
                UserDTO userInfo = userInfoMap.get(record.getUserId());
                if (ObjectUtils.isNotEmpty(userInfo)) {
                    vo.setUserName(userInfo.getName());
                    vo.setUserIcon(userInfo.getIcon());
                } else {
                    vo.setUserName("");
                    vo.setUserIcon("");
                }
                //3.2评论的评论则还行填充targetUserName，无需展示被评论数量
                if (ObjectUtils.isNotEmpty(record.getTargetReplyId())) {
                    userInfo = userInfoMap.get(record.getTargetUserId());
                    if (ObjectUtils.isNotEmpty(userInfo)) {
                        vo.setTargetUserName(userInfo.getName());
                    } else {
                        vo.setTargetUserName("");
                    }
                }
            }
            //3.3判断是否点赞过
            vo.setLiked(likedList.contains(vo.getId()));
            voList.add(vo);
        }


        //4、封装PageDTO返回

        return PageDTO.of(pageResult, voList);
    }

    /**
     * 管理端 - 管理端显示或隐藏评论
     *
     * @param id
     * @param hidden
     */
    @Override
    public void hiddenChange(Long id, Boolean hidden) {
        if (ObjectUtils.isEmpty(id) || ObjectUtils.isEmpty(hidden)) {
            throw new BadRequestException("请求参数不能为空");
        }
        boolean updateResult = updateById(new InteractionReply().setId(id).setHidden(hidden));
        AssertUtils.isTrue(updateResult, "更新失败");
    }
}
